﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace foxAudio2Word
{
    public partial class Form1 : Form
    {
        //标记线程中已完成的文件数量
        int numFinished = 0;
        //把文件分成若干块
        int duration = 0;
        //用于记录识别时间的变量
        long timerCount;
        //标记识别线程完成的flag
        bool taskFinished;
        //存储识别结果的全局变量
        string tempResult;
        //默认的识别结果文本框字体大小为11
        int myFontSize = 11;
        public Form1()
        {
            InitializeComponent();
            //初始化欢迎语句
            string strMsgHello = "欢迎使用云狐语音识别软件。"+
                "注意，第一次使用请先去百度云官网申请API Key和Secret Key。";
            //显示欢迎语句
            richTextBox1.Text = strMsgHello;
            //读取百度Akey和Skey
            try
            {
                // 创建一个 StreamReader 的实例来读取文件 
                // using 语句也能关闭 StreamReader
                using (StreamReader sr = new StreamReader("百度ASkey.txt"))
                {
                    foxConfigClass.myAPIKey = sr.ReadLine();
                    foxConfigClass.mySecretKey = sr.ReadLine();

                    //测试
                    //richTextBox1.Text = foxConfigClass.myAPIKey + "\n\r" +
                    //    foxConfigClass.mySecretKey;
                }
            }
            catch (Exception e)
            {
                // 向用户显示出错消息
                Console.WriteLine("文件不可读：");
                Console.WriteLine(e.Message);
            }
        }
        /// <summary>
        /// 执行cmd命令的通用函数
        /// </summary>
        /// <param name="cmdStr">命令参数</param>
        /// <returns></returns>
        private string myCmdFun(string cmdStr)
        {
            try
            {
                Process CmdProcess = new Process();
                CmdProcess.StartInfo.FileName = "cmd.exe";

                CmdProcess.StartInfo.CreateNoWindow = true;         // 不创建新窗口    
                CmdProcess.StartInfo.UseShellExecute = false;       //不启用shell启动进程  
                CmdProcess.StartInfo.RedirectStandardInput = true;  // 重定向输入    
                CmdProcess.StartInfo.RedirectStandardOutput = true; // 重定向标准输出    
                CmdProcess.StartInfo.RedirectStandardError = true;  // 重定向错误输出  

                //CmdProcess.StartInfo.Arguments = "/c " + "=====cmd命令======";//“/C”表示执行完命令后马上退出
                //string cmdStr = "ffmpeg -y  -i 003_16k.wav  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 16k.pcm";
                CmdProcess.StartInfo.Arguments = "/c " + cmdStr;//“/C”表示执行完命令后马上退出  
                CmdProcess.Start();//执行  

                string temp = CmdProcess.StandardOutput.ReadToEnd();//输出  

                CmdProcess.WaitForExit();//等待程序执行完退出进程  

                CmdProcess.Close();//结束

                //richTextBox1.Text = temp;

                return temp;
            }
            catch (Exception ex)
            {
                //richTextBox1.Text = ex.ToString();
                return ex.ToString();
            }
        }
        ///分割的时间单位应该是秒
        ///分割音频文件
        private void foxAudioCut(string filename,int timePos,int duration,int fileIndex)
        {
            //string tempCmdStr = "ffmpeg -i 003_16k.wav -ss 10 -t 10 003_1.wav";
            string tempCmdStr = "ffmpeg -y -i "+filename+
                " -ss "+timePos.ToString()
                +" -t "+duration.ToString()
                +" "+ "temp\\" + fileIndex.ToString()+".wav";

            myCmdFun(tempCmdStr);
        }
        /// <summary>
        /// 把目标音频文件转换为百度语音能够识别的文件
        /// </summary>
        /// <param name="filename"></param>
        private string foxAudioConvert(string filename,int fileIndex)
        {
            //临时工作夹目录设置为“temp”
            string resultFileName = "Convert_" + fileIndex.ToString() + ".wav";
            //注意这句含有两个“temp\\”
            string tempCmdStr = "ffmpeg -y  -i "+ "temp\\" + filename
                +"  -acodec pcm_s16le -ac 1 -ar 16000 " 
                + "temp\\" +resultFileName;
            myCmdFun(tempCmdStr);

            return resultFileName;
        }
        /// <summary>
        /// 获取音频文件的持续时间信息
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        private int foxGetAudioDuration(string filename)
        {
            //使用命令行要非常小心对空格的处理
            string tempCmdStr = "ffprobe -v quiet -print_format json -show_streams "
                + filename;
            string result = myCmdFun(tempCmdStr);
            //结果使用json格式解析
            JObject jo = (JObject)JsonConvert.DeserializeObject(result);
            string audioDuration = jo["streams"][0]["duration"].ToString();
            //直接返回整形数据，单位是秒
            int durationSecond = (int)Math.Ceiling(System.Convert.ToDouble(audioDuration));
            //转成分钟表示
            int durationMinute = (durationSecond / 60) + 1;

            return durationMinute;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    //初始化操作
                    //标记识别进度的变量
                    duration = 1;
                    numFinished = 0;
                    //计时变量
                    timerCount = 0;
                    //线程未开始
                    taskFinished = false;
                    //初始化识别结果字符串
                    tempResult = "";
                    //按键逻辑
                    button1.Enabled = false;
                    //开始计时
                    timer1.Enabled = true;
                    //显示信息
                    richTextBox1.Text = "正在识别中，请稍候。。。";
                    //多线程支持
                    var t1 = new Task(() =>
                    {
                        //foxSpeechDemo fd = new foxSpeechDemo("vP5q2VeXl0dVCatqz4uSGNV5", "xyDhSYh0udgCxEGLvjoYRBIWzABwZG4e");
                        foxSpeechDemo fd = new foxSpeechDemo(foxConfigClass.myAPIKey, foxConfigClass.mySecretKey);
                        //注意：文件路径里面如果含有空格需要另外处理
                        string tempFilePath = Path.GetFullPath(openFileDialog1.FileName);
                        //对包含空格字符的文件路径进行处理
                        if (tempFilePath.Contains(" "))
                        {
                            string tempCopyFilePath = "tempCopyFile\\tempCopy.wav";
                            //复制文件
                            File.Copy(tempFilePath, tempCopyFilePath, true);
                            //这个是处理后的语音文件副本路径
                            tempFilePath = tempCopyFilePath;
                        }
                        //获取音频文件持续时间信息
                        duration = foxGetAudioDuration(tempFilePath);
                        //主要的长语音识别逻辑
                        //将音频文件分成块，每块的长度默认为1分钟
                        for (int i = 0; i < duration; i++)
                        {
                            //首先分割文件
                            foxAudioCut(tempFilePath, i * 60, 60, i);
                            //然后转换格式
                            string tempConvertFileName = foxAudioConvert(i.ToString() + ".wav", i);
                            //解析json
                            string tempStr = fd.AsrData("temp\\" + tempConvertFileName);
                            //记录文件信息，存放在执行文件目录的log.txt文件中
                            //注意这里要用“\r\n”才能实现换行的效果
                            MyFileIO.Write("log.txt", DateTime.Now.ToString() + " 文件路径：" + tempFilePath + "的原始json数据如下：\r\n");
                            //记录原始json数据
                            MyFileIO.Write("log.txt", tempStr + "\r\n");
                            if (!tempStr.Equals("无法连接到远程服务器"))
                            {
                                JObject jo = (JObject)JsonConvert.DeserializeObject(tempStr);
                                if (jo["err_msg"].ToString().Equals("success."))
                                {
                                    string result = jo["result"][0].ToString();
                                    tempResult += result;
                                }
                            }
                            else
                            {
                                tempResult += "无法连接到远程服务器\n";
                            }
                            //已完成的文件数量
                            numFinished++;
                        }
                        //标记task线程完成的flag
                        taskFinished = true;
                    }); 
                    t1.Start();
                }
                catch (Exception ex)
                {
                    richTextBox1.Text = ex.ToString();
                    //按键逻辑
                    button1.Enabled = true;
                    //timer1.Enabled = true;
                    //tempResult = "";
                    //taskFinished = false;
                }
            }
        }
        /// <summary>
        /// 测试用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    string tempFilePath = Path.GetFullPath(openFileDialog1.FileName);
                    if (tempFilePath.Contains(" "))
                        richTextBox1.Text += "\n路径中有空格\n";
                    richTextBox1.Text += tempFilePath + "\n";
                    //string tempFileName = "tempCopy.wav";
                    //richTextBox1.Text += tempFileName + "\n";
                    string tempCopyFilePath = "tempCopyFile\\tempCopy.wav";
                    richTextBox1.Text += tempCopyFilePath;
                    //复制文件
                    File.Copy(tempFilePath, tempCopyFilePath, true);
                    richTextBox1.Text += "复制成功";
                }
                catch(Exception ex)
                {
                    richTextBox1.Text = ex.ToString();
                }
            }
        }

        private void 设置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foxConfigForm fcf = new foxConfigForm();
            fcf.ShowDialog();
        }

        private void TsbuttonSelectAll_Click(object sender, EventArgs e)
        {
            richTextBox1.SelectAll();
        }

        private void TsbuttonCopy_Click(object sender, EventArgs e)
        {
            richTextBox1.Copy();
        }

        private void FontIncreaseToolBt_Click(object sender, EventArgs e)
        {
            //不能超过操作系统设置的最大字体
            if (myFontSize < System.Single.MaxValue - 2)
                //按键后自增
                myFontSize++;
            //增大字体
            richTextBox1.Font = new Font(System.Drawing.SystemFonts.DefaultFont.Name, myFontSize);
        }

        private void FontDecreaseToolBt_Click(object sender, EventArgs e)
        {
            //不能小于0
            if (myFontSize > 1)
                //按键后自增
                myFontSize--;
            //减少字体
            richTextBox1.Font = new Font(System.Drawing.SystemFonts.DefaultFont.Name, myFontSize);
        }

        private void 帮助ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foxRightForm frf = new foxRightForm();
            frf.ShowDialog();
        }

        private void Timer1_Tick(object sender, EventArgs e)
        {
            timerCount++;
            if(taskFinished)
            {
                //按键逻辑
                timer1.Enabled = false;
                //进度条完成
                progressBar1.Value = progressBar1.Maximum;
                //让左边文本框显示的信息，可以加入识别的图片信息和简单的统计信息
                //单位为秒
                string tempUseTime = (timerCount * 0.1).ToString();
                //显示识别结果
                richTextBox1.Text = "本次识别耗时" + tempUseTime + "秒。\n" +
                    "识别结果如下：\n" + tempResult;
                //按键逻辑
                button1.Enabled = true;
                //停止计时
                timerCount = 0;
            }
            else
            {
                //进度条的进度增加
                progressBar1.Value = (int)((progressBar1.Maximum * 0.9 / duration)
                                       * numFinished);
            }
        }

        private void ProgressBar1_Click(object sender, EventArgs e)
        {

        }
    }
}
